#pragma once

#include "znx_defs.h"
#include "znx_crc.h"
#include "znx_string.h"
#include "znx_array.h"
#include "znx_thread_base.h"


typedef struct {
    znx_str_t                   key;
    void                        *data;
    size_t                      weight;
} znx_chash_node_t;


static inline void
znx_chash_node_init(znx_chash_node_t *node,
    znx_str_t *key, void *data, size_t weight)
{
    assert(key != NULL);
    node->key = *key;
    node->data = data;
    node->weight = weight;
}


typedef struct {
    uint32_t                    crc_key;
    znx_chash_node_t            *real_node;
} znx_chash_vnode_t;


static inline int
znx_chash_vnode_cmp_handle(const void *a, const void *b)
{
    znx_chash_vnode_t   *anode = (znx_chash_vnode_t *)a;
    znx_chash_vnode_t   *bnode = (znx_chash_vnode_t *)b;

    if (anode->crc_key < bnode->crc_key) {
        return -1;
    }

    if (anode->crc_key > bnode->crc_key) {
        return 1;
    }

    if (anode->real_node->key.len < bnode->real_node->key.len) {
        return -1;
    }

    if (anode->real_node->key.len > bnode->real_node->key.len) {
        return 1;
    }

    return znx_strncmp(anode->real_node->key.data,
        bnode->real_node->key.data, anode->real_node->key.len);
}


static inline void
znx_chash_vnode_init(znx_chash_vnode_t *vnode,
    znx_chash_node_t *node, int idx)
{
    uint32_t                    crc;
    u_char                      *end;
    u_char                      buf[128] = { 0 };

    znx_crc32_init(crc);
    znx_crc32_update(&crc, node->key.data, node->key.len);
    end = znx_snprintf(buf, 128, "#%d-%d-%d#", crc, idx, node->key.len);
    znx_crc32_update(&crc, buf, (size_t)(end - buf));
    znx_crc32_final(crc);

    vnode->crc_key = crc;
    vnode->real_node = node;
}


typedef struct {
    size_t                      replace;
    znx_array_t                 *nodes;
    size_t                      nvnodes;
    znx_chash_vnode_t           *vnodes;
    size_t                      total_weight;        
} znx_chash_t;


#define ZNX_CHASH_DEF_REPLACE    (256)


znx_chash_t *znx_chash_create(size_t replace);

void znx_chash_add_node(znx_chash_t *chash, znx_str_t *key, void *data, size_t weight);

void znx_chash_build(znx_chash_t *chash);

typedef znx_bool_t (*znx_chash_node_check_pt) (znx_chash_node_t *node, void *user_data);


typedef struct {
    void    *server;
    void    *balance_server;
} znx_chash_result_t;


znx_chash_result_t znx_chash_get(znx_chash_t *chash,
    znx_str_t *key, int balance,
    znx_chash_node_check_pt checker,
    void *user_data,
    znx_bool_t must_get);

void znx_chash_destroy(znx_chash_t *chash);

